/*****************************************************************************
 * Copyright (C) Stacy Curl. All rights reserved.                            *
 * ------------------------------------------------------------------------- *
 * The software in this package is published under the terms of the BSD      *
 * style license a copy of which has been included with this distribution in *
 * the LICENSE.txt file.                                                     *
 *****************************************************************************/
package picounit.features.parameter_constraints;

import picounit.ByteArrayParameterConstraints;
import picounit.DoubleParameterConstraints;
import picounit.Future;
import picounit.IntegerParameterConstraints;
import picounit.Is;
import picounit.LongParameterConstraints;
import picounit.ObjectParameterConstraints;
import picounit.StringParameterConstraints;
import picounit.Verify;
import picounit.features.base.ProxyFactory;
import picounit.features.constraint_store.ConstraintStore;

public class JMockConstraints implements Is {
	private final ProxyFactory proxyFactory;
	private final IntegerParameterConstraints integerParameterConstraints;
	private final LongParameterConstraints longParameterConstraints;
	private final DoubleParameterConstraints doubleParameterConstraints;
	private final StringParameterConstraints stringParameterConstraints;
	private final ObjectParameterConstraints objectParameterConstraints;
	private final ByteArrayParameterConstraints byteArrayParameterConstraints;
	private final Verify verify;

	public JMockConstraints(ConstraintStore constraintStore, ProxyFactory proxyFactory, Verify verify) {
		this(new JMockIntegerConstraints(constraintStore), new JMockLongConstraints(constraintStore),
			new JMockDoubleConstraints(constraintStore), new JMockStringConstraints(constraintStore),
			new JMockObjectConstraints(constraintStore), new JMockByteArrayConstraints(constraintStore),
			proxyFactory, verify);
	}

	public JMockConstraints(IntegerParameterConstraints integerParameterConstraints,
		LongParameterConstraints longParameterConstraints, DoubleParameterConstraints doubleParameterConstraints,
		StringParameterConstraints stringParameterConstraints, ObjectParameterConstraints objectParameterConstraints,
		ByteArrayParameterConstraints byteArrayConstraints, ProxyFactory proxyFactory, Verify verify) {

		this.integerParameterConstraints = integerParameterConstraints;
		this.longParameterConstraints = longParameterConstraints;
		this.doubleParameterConstraints = doubleParameterConstraints;
		this.stringParameterConstraints = stringParameterConstraints;
		this.objectParameterConstraints = objectParameterConstraints;
		this.byteArrayParameterConstraints = byteArrayConstraints;
		this.proxyFactory = proxyFactory;
		this.verify = verify;
	}

	public <T> T instanceOf(Class<T> instanceOf) {
		return proxyFactory.create(instanceOf, new InstanceOfInvocationHandler<T>(instanceOf));
	}

	@SuppressWarnings("unchecked")
	public <T> Future<T> future(Class<T> futureType) {
		return proxyFactory.create(Future.class,
			new FutureInvocationHandler(new FutureImpl(futureType, verify)));
	}

	///////////////////////////////////////////////////////////////////////////////////////////////
	// IntegerConstraints
	///////////////////////////////////////////////////////////////////////////////////////////////
	public int anInteger() {
		return integerParameterConstraints.anInteger();
	}

	public int oneOf(int ... oneOf) {
		return integerParameterConstraints.oneOf(oneOf);
	}

	public int notEqualTo(int notEqual) {
		return integerParameterConstraints.notEqualTo(notEqual);
	}
	
	public int neitherOf(int ... neitherOf) {
		return integerParameterConstraints.neitherOf(neitherOf);
	}

	public int lessThan(int upperLimit) {
		return integerParameterConstraints.lessThan(upperLimit);
	}

	public int lessThanOrEqualTo(int upperLimit) {
		return integerParameterConstraints.lessThanOrEqualTo(upperLimit);
	}

	public int greaterThan(int lowerLimit) {
		return integerParameterConstraints.greaterThan(lowerLimit);
	}

	public int greaterThanOrEqualTo(int lowerLimit) {
		return integerParameterConstraints.greaterThanOrEqualTo(lowerLimit);
	}

	public int between(int lowerLimit, int upperLimit) {
		return integerParameterConstraints.between(lowerLimit, upperLimit);
	}

	public int notBetween(int lowerLimit, int upperLimit) {
		return integerParameterConstraints.notBetween(lowerLimit, upperLimit);
	}
	
	public int almostEqualTo(int equalTo, int errorAllowed) {
		return integerParameterConstraints.almostEqualTo(equalTo, errorAllowed);
	}

	///////////////////////////////////////////////////////////////////////////////////////////////
	// ExtensibleLongConstraints
	///////////////////////////////////////////////////////////////////////////////////////////////
	public long aLong() {
		return longParameterConstraints.aLong();
	}
	
	public long oneOf(long ... oneOf) {
		return longParameterConstraints.oneOf(oneOf);
	}
	
	public long neitherOf(long ... neitherOf) {
		return longParameterConstraints.neitherOf(neitherOf);
	}
	
	public long notEqualTo(long notEqual) {
		return longParameterConstraints.notEqualTo(notEqual);
	}
	
	public long lessThan(long upperLimit) {
		return longParameterConstraints.lessThan(upperLimit);
	}

	public long lessThanOrEqualTo(long upperLimit) {
		return longParameterConstraints.lessThanOrEqualTo(upperLimit);
	}
	
	public long greaterThan(long lowerLimit) {
		return longParameterConstraints.greaterThan(lowerLimit);
	}
	
	public long greaterThanOrEqualTo(long lowerLimit) {
		return longParameterConstraints.greaterThanOrEqualTo(lowerLimit);
	}
	
	public long between(long lowerLimit, long upperLimit) {
		return longParameterConstraints.between(lowerLimit, upperLimit);
	}
	
	public long notBetween(long lowerLimit, long upperLimit) {
		return longParameterConstraints.notBetween(lowerLimit, upperLimit);
	}
	
	public long almostEqualTo(long equalTo, long errorAllowed) {
		return longParameterConstraints.almostEqualTo(equalTo, errorAllowed);
	}

	///////////////////////////////////////////////////////////////////////////////////////////////
	// DefaultDoubleConstraints
	///////////////////////////////////////////////////////////////////////////////////////////////
	public double aDouble() {
		return doubleParameterConstraints.aDouble();
	}
	
	public double oneOf(double ... oneOf) {
		return doubleParameterConstraints.oneOf(oneOf);
	}
	
	public double neitherOf(double ... neitherOf) {
		return doubleParameterConstraints.neitherOf(neitherOf);
	}
	
	public double notEqualTo(double notEqual) {
		return doubleParameterConstraints.notEqualTo(notEqual);
	}
	
	public double lessThan(double upperLimit) {
		return doubleParameterConstraints.lessThan(upperLimit);
	}
	
	public double lessThanOrEqualTo(double upperLimit) {
		return doubleParameterConstraints.lessThanOrEqualTo(upperLimit);
	}
	
	public double greaterThan(double lowerLimit) {
		return doubleParameterConstraints.greaterThan(lowerLimit);
	}
	
	public double greaterThanOrEqualTo(double lowerLimit) {
		return doubleParameterConstraints.greaterThanOrEqualTo(lowerLimit);
	}
	
	public double between(double lowerLimit, double upperLimit) {
		return doubleParameterConstraints.between(lowerLimit, upperLimit);
	}
	
	public double notBetween(double lowerLimit, double upperLimit) {
		return doubleParameterConstraints.notBetween(lowerLimit, upperLimit);
	}
	
	public double almostEqualTo(double equalTo, double errorAllowed) {
		return doubleParameterConstraints.almostEqualTo(equalTo, errorAllowed);
	}
	
	///////////////////////////////////////////////////////////////////////////////////////////////
	// ByteArrayConstraints
	///////////////////////////////////////////////////////////////////////////////////////////////
	
	public byte[] aByteArray() {
		return byteArrayParameterConstraints.aByteArray();
	}
	
	///////////////////////////////////////////////////////////////////////////////////////////////
	// DefaultStringConstraints
	///////////////////////////////////////////////////////////////////////////////////////////////
	public String aString() {
		return stringParameterConstraints.aString();
	}
	
	public String oneOf(String ... oneOf) {
		return stringParameterConstraints.oneOf(oneOf);
	}

	public String neitherOf(String ... neitherOf) {
		return stringParameterConstraints.neitherOf(neitherOf);
	}

	public String notEqualTo(String notEqual) {
		return stringParameterConstraints.notEqualTo(notEqual);
	}

	public String aStringContaining(String toContain) {
		return stringParameterConstraints.aStringContaining(toContain);
	}

	public String aStringNotContaining(String notToContain) {
		return stringParameterConstraints.aStringNotContaining(notToContain);
	}

	public String equalToIgnoringCase(String toEqual) {
		return stringParameterConstraints.equalToIgnoringCase(toEqual);
	}
	
	public String aStringMatching(String pattern) {
		return stringParameterConstraints.aStringMatching(pattern);
	}
	
	public String aStringNotMatching(String pattern) {
		return stringParameterConstraints.aStringNotMatching(pattern);
	}

	public String aNullString() {
		return stringParameterConstraints.aNullString();
	}

	public String notANullString() {
		return stringParameterConstraints.notANullString()	;
	}

	///////////////////////////////////////////////////////////////////////////////////////////////
	// TypedConstraintsImpl
	///////////////////////////////////////////////////////////////////////////////////////////////
	public Object notEqual(Object notEqual) {
		return objectParameterConstraints.notEqual(notEqual);
	}
	
	public Object anObject() {
		return objectParameterConstraints.anObject();
	}
	
	public Object aNullObject() {
		return objectParameterConstraints.aNullObject();
	}
	
	public Object notANullObject() {
		return objectParameterConstraints.notANullObject();
	}
	
	public Object oneOf(Object ... oneOf) {
		return objectParameterConstraints.oneOf(oneOf);
	}
	
	public Object neitherOf(Object ... neitherOf) {
		return objectParameterConstraints.neitherOf(neitherOf);
	}
}
